package com.lucky.common.config.security;

import com.lucky.common.cache.RightCache;
import com.lucky.common.enums.AppConst;
import com.lucky.common.mapper.PermMapper;
import com.lucky.common.mapper.RoleMapper;
import com.lucky.common.mapper.UserMapper;
import com.lucky.common.pojo.po.UserPO;
import com.lucky.common.service.UserService;
import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.*;

@Service
public class AppUserDetailsService implements UserDetailsService {
    @Value("${server.servlet.context-path}")
    String app;

    @Resource
    RightCache rightCache = null;

    @Resource
    PermMapper permMapper;

    @Resource
    UserMapper userMapper = null;

    @Resource
    RoleMapper roleMapper = null;

    @Resource
    PasswordEncoder passwordEncoder;

    @Resource
    UserService userService;


    @Override
    public AppUserDetail loadUserByUsername(String username) throws UsernameNotFoundException {
            UserPO po = userMapper.getUserByUserCode(username);
            Assert.notNull(po, "用户名或密码错误");
            // 从数据库或其他来源获取用户的权限（角色）
            List<String> rights = new ArrayList<>(1000);
            List<String> roles = roleMapper.queryRoles(username);
            roles.forEach(role -> rights.addAll(rightCache.roleUrlMap.get(role)));
            List<GrantedAuthority> authorities = new ArrayList<>();
            rights.addAll(roles);
            rights.stream().filter(Objects::nonNull).map(s->s.startsWith("/")?s:"/"+s).sorted().forEach(r->authorities.add(new SimpleGrantedAuthority(r)));
//            rights.stream().filter(Objects::nonNull).forEach(authorities::add);

        UserDetails userDetails = User.builder()
                    .username(username)
                    .password(po.getPassword()) // 确保这里的密码是加密后的
//                    .roles(roles.toArray(new String[0])) // 角色信息，根据实际情况转换
                    .authorities(authorities)
                    // 显式设置账户状态（默认都是true，但建议显式指定以提高可读性）
                    .accountExpired(false)
                    .accountLocked(false)
                    .credentialsExpired(false)
                    .disabled(false)
                    .build();

        AppUserDetail user = new AppUserDetail(userDetails, roles, rights);
        user.setUserPO(po);
        return user;
    }


    public void login(HttpSession session, String username, String password) {

        // 3. 调用UserDetailsService查询用户
        AppUserDetail userDetails = this.loadUserByUsername(username);
        // 4. 密码比对（实际由Spring Security自动完成）
        if (!passwordEncoder.matches(password, userDetails.getPassword())) {
            throw new BadCredentialsException("密码错误");
        }
        // 5. 创建已认证的令牌
        UsernamePasswordAuthenticationToken authenticated = new UsernamePasswordAuthenticationToken(
                userDetails,
                null,
                userDetails.getAuthorities()
        );

        // 6. 关键：登录成功后必须保存认证信息。

        SecurityContext context = SecurityContextHolder.getContext();
        context.setAuthentication(authenticated);

        session.setAttribute(AppConst.security, context); // 同步到Session
        session.setAttribute(AppConst.user,  userDetails);
        session.setAttribute(AppConst.userPO,userDetails.getUserPO());
        session.setAttribute(AppConst.roles, userDetails.getRoles());
        session.setAttribute(AppConst.perms, userDetails.getPerms());

        Authentication auth = context.getAuthentication();
        System.out.println("设置后：" + auth.getName() + ", " + auth.isAuthenticated());

    }
}
